﻿using System.Collections.Generic;

namespace GX
{
    public class Event
    {
        public const int ValueType_Int = 1;
        public const int ValueType_Float = 2;

        static readonly Stack<Event> s_stack = new Stack<Event>();
        static internal Event From(int type, object body, string name)
        {
            Event evt = null;
            if (s_stack.Count == 0)
                evt = new Event();
            else
            {
                evt = s_stack.Pop();
            }
            evt.Reset(type, body,name,true);
            return evt;
        }
        static internal void To(Event evt)
        {
            evt.Reset(0,null,null,true);
            if (s_stack.Count < 64)
                s_stack.Push(evt);
        }
       

        Dictionary<int, int> _keyToType=null;
        Dictionary<int, int> _intValues=null;
        Dictionary<int, float> _floatValues=null;
        int _type;
        string _name;
        object _body;
        public int type { get { return _type; } }
        public string name { get { return _name; } }
        public object body { get { return _body; } }
        public int parameterCount { get { return null == _keyToType ? 0 : _keyToType.Count; } }
        public bool HasParameter(int key)
        {
            return null != _keyToType && _keyToType.ContainsKey(key);
        }
        void Add(int key, int type)
        {
            int curType=0;
            
            if (null != _keyToType && _keyToType.TryGetValue(key, out curType))
            {
                if (curType == type)
                    return;
                DeleteParameter(key);
            }
            if (null == _keyToType)
                _keyToType = PoolManager.GetDictionary<int, int>();
           
            _keyToType[key] = type;
            
            if (type == ValueType_Int)
            {
                if (null == _intValues)
                    _intValues = PoolManager.GetDictionary<int,int>();
            }
            else if (type == ValueType_Float)
            {
                if (null == _floatValues)
                    _floatValues = PoolManager.GetDictionary<int, float>();
            }
        }
        public void DeleteParameter(int key)
        {
            if (null == _keyToType)
                return;
            int type;
            if (!_keyToType.TryGetValue(key, out type))
                return;

            _keyToType.Remove(key);

            if (0 == _keyToType.Count)
            {
                PoolManager.Release(_keyToType);
                _keyToType = null;
            }
            if (type == ValueType_Int)
            {
                _intValues.Remove(key);
                if (0 == _intValues.Count)
                {
                    PoolManager.Release( _intValues);
                    _intValues = null;
                }
            }
            else if (type == ValueType_Float)
            {
                _floatValues.Remove(key);
                if (0 == _floatValues.Count)
                {
                    PoolManager.Release( _floatValues);
                    _floatValues = null;
                }
            }
        }
        public void ClearParameters()
        {
            if (null == _keyToType)
                return;
            PoolManager.Release( _keyToType);
            _keyToType = null;
            if (null != _intValues)
            {
                PoolManager.Release( _intValues);
                _intValues = null;
            }
            if (null != _floatValues)
            {
                PoolManager.Release(_floatValues);
                _floatValues = null;
            }
        }
        public void SetInt(int key, int value)
        {
            Add(key,ValueType_Int);
            _intValues[key] = value;
        }
       
        public void SetFloat(int key, float value)
        {
            Add(key, ValueType_Float);
            _floatValues[key] = value;
        }
        public int GetInt(int key, int defValue)
        {
            int ret;
            if (null != _intValues && _intValues.TryGetValue(key, out ret))
                return ret;
            return defValue;
        }
        public int GetInt(int key)
        {
            return GetInt(key,0);
        }
        
        public float GetFloat(int key, float defValue)
        {
            float ret;
            if (null != _floatValues && _floatValues.TryGetValue(key, out ret))
                return ret; 
            return defValue;
        }
        public float GetFloat(int key)
        {
            return GetFloat(key, 0f);
        }
        public void CopyFrom(Event args)
        {
            this.ClearParameters();
            if (null == args._keyToType)
                return;
            var iter = args._keyToType.GetEnumerator();
            while (iter.MoveNext())
            {
                var cur = iter.Current;
                if (cur.Value == ValueType_Int)
                    this.SetInt(cur.Key,args._intValues[cur.Key]);
                else if (cur.Value == ValueType_Float)
                    this.SetFloat(cur.Key, args._floatValues[cur.Key]);
            }
        }
        public void Reset(int type, object body, string name=null, bool clearParameters = true)
        {
            _type = type;
            _body = body;
            _name = name ?? string.Empty;
            if (clearParameters)
                this.ClearParameters();
        }
    }
}